import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:aliplayer_widget/utils/log_util.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:yyshort/common/apis/apis.dart';
import 'package:yyshort/common/model/useInfo_model.dart';
import 'package:yyshort/common/store/store.dart';
import 'package:yyshort/common/utils/device_info_util.dart';
import 'package:yyshort/common/utils/encryption_utils.dart';
import 'package:yyshort/common/utils/network_provider.dart';
import 'package:yyshort/common/utils/utils.dart';
import 'package:yyshort/common/values/values.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart' hide FormData, Response;

/*
  * http 操作类
  *
  * 手册
  * https://github.com/flutterchina/dio/blob/master/README-ZH.md
  *
  * 从 3 升级到 4
  * https://github.com/flutterchina/dio/blob/master/migration_to_4.x.md
*/
class HttpUtil {
  static HttpUtil _instance = HttpUtil._internal();
  factory HttpUtil() => _instance;

  late Dio dio;
  CancelToken cancelToken = new CancelToken();

  HttpUtil._internal() {
    // BaseOptions、Options、RequestOptions 都可以配置参数，优先级别依次递增，且可以根据优先级别覆盖参数
    BaseOptions options = new BaseOptions(
      // 请求基地址,可以包含子路径
      baseUrl: kDebugMode ? DEBUG_API_URL : RELEASE_API_URL,
      // baseUrl: RELEASE_API_URL,

      // baseUrl: storage.read(key: STORAGE_KEY_APIURL) ?? SERVICE_API_BASEURL,
      //连接服务器超时时间，单位是毫秒.
      connectTimeout: Duration(milliseconds: 5000),

      // 响应流上前后两次接受到数据的间隔，单位为毫秒。
      receiveTimeout: Duration(milliseconds: 30000),

      // Http请求头.
      headers: {},

      /// 请求的Content-Type，默认值是"application/json; charset=utf-8".
      /// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,
      /// 可以设置此选项为 `Headers.formUrlEncodedContentType`,  这样[Dio]
      /// 就会自动编码请求体.
      // contentType: 'multipart/form-data; charset=utf-8',
      contentType:
          Headers.multipartFormDataContentType, // ✅ 自动添加 boundary，兼容性更好
      /// [responseType] 表示期望以那种格式(方式)接受响应数据。
      /// 目前 [ResponseType] 接受三种类型 `JSON`, `STREAM`, `PLAIN`.
      ///
      /// 默认值是 `JSON`, 当响应头中content-type为"application/json"时，dio 会自动将响应内容转化为json对象。
      /// 如果想以二进制方式接受响应数据，如下载一个二进制文件，那么可以使用 `STREAM`.
      ///
      /// 如果想以文本(字符串)格式接收响应数据，请使用 `PLAIN`.
      responseType: ResponseType.json,
    );

    dio = new Dio(options);
    // 添加拦截器
    dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) {
          return handler.next(options); //continue

          // 如果你想完成请求并返回一些自定义数据，你可以resolve一个Response对象 `handler.resolve(response)`。
          // 这样请求将会被终止，上层then会被调用，then中返回的数据将是你的自定义response.
          //
          // 如果你想终止请求并触发一个错误,你可以返回一个`DioError`对象,如`handler.reject(error)`，
          // 这样请求将被中止并触发异常，上层catchError会被调用。
          // 取消请求

          // DioException error = DioException(
          //   requestOptions: options,
          //   type: DioExceptionType.badResponse,
          //   message: "请求取消",
          // );
          // return handler.reject(error); // 终止请求并触发错误
        },
        onResponse: (response, handler) {
          // Do something with response data
          Map<dynamic, dynamic> decrypted = {};
          if (kDebugMode ? false : true) {
            decrypted = EncryptionUtils.decryptData(response.data as String);
            print('解密结果: $decrypted');
          } else {
            decrypted = jsonDecode(response.data) as Map<dynamic, dynamic>;
          }

          // 如果响应数据是 Map 类型，直接返回
          if (decrypted['code'] == 1) {
            return handler.next(response);
          } else if (decrypted['code'] == 2402) {
            return handler.next(response); // continue
          } else if (decrypted['code'] == 2102) {
            //2102 余额不足，|| 2203上一集未解锁
            return handler.next(response);
          } else {
            // 错误处理
            ErrorEntity eInfo = ErrorEntity(
              code: decrypted['code'] ?? -1,
              message: decrypted['msg'] ?? '未知错误',
            );
            onError(eInfo);
            return handler.next(response); // continue
          }
          // 如果你想终止请求并触发一个错误,你可以 reject 一个`DioError`对象,如`handler.reject(error)`，
          // 这样请求将被中止并触发异常，上层catchError会被调用。
        },
        onError: (DioException e, handler) {
          // Do something with response error
          Loading.dismiss();
          ErrorEntity eInfo = createErrorEntity(e);
          onError(eInfo);
          // Response response = Response(
          //   requestOptions: e.requestOptions, // 使用错误中的请求配置
          //   statusCode: e.response?.statusCode ?? 500, // 保留原状态码或使用默认错误码
          //   // 添加自定义响应数据
          //   data: {
          //     'success': false,
          //     'errorCode': eInfo.code,
          //     'errorMessage': eInfo.message,
          //     'originalError': e.message, // 可选：保留原始错误信息
          //   },
          // );
          // handler.resolve(response);

          return handler.next(e); //continue
          // 如果你想完成请求并返回一些自定义数据，可以resolve 一个`Response`,如`handler.resolve(response)`。
          // 这样请求将会被终止，上层then会被调用，then中返回的数据将是你的自定义response.
        },
      ),
    );
  }

  /*
   * error统一处理
   */

  // 错误处理
  void onError(ErrorEntity eInfo) {
    print('error.code -> ${eInfo.code}, error.message -> ${eInfo.message}');
    switch (eInfo.code) {
      case 401:
        UserInfo().clearUserInfo();
        UserAPI.guestLogin();
        // EasyLoading.showError(eInfo.message);
        break;
      case 1000:
        EasyLoading.showError('token刷新失败，请重新登录'.tr);
        break;
      case 2000:
        EasyLoading.showError('参数错误'.tr);
        break;
      case 2101:
        EasyLoading.showError('用户不存在'.tr);
        break;
      case 2201:
        EasyLoading.showError('短剧不存在'.tr);
        break;
      case 10001:
        EasyLoading.showError('签名错误'.tr);
        break;
      case 10002:
        EasyLoading.showError('解密失败'.tr);
      case -10086:
        Get.find<NetworkService>().showNoNetworkAlert();
      default:
        EasyLoading.showError(eInfo.message);
        break;
    }
  }

  // 错误信息
  ErrorEntity createErrorEntity(DioException error) {
    switch (error.type) {
      case DioExceptionType.cancel:
        return ErrorEntity(code: -1, message: "请求取消");
      case DioExceptionType.connectionTimeout:
        return ErrorEntity(code: -10086, message: "连接超时".tr);
      case DioExceptionType.sendTimeout:
        return ErrorEntity(code: -1, message: "网络不佳".tr); //请求超时
      case DioExceptionType.receiveTimeout:
        return ErrorEntity(code: -1, message: "响应超时".tr);
      case DioExceptionType.cancel:
        return ErrorEntity(code: -1, message: "请求取消");
      case DioExceptionType.badResponse:
        {
          try {
            int errCode = error.response != null
                ? error.response!.statusCode!
                : -1;
            // String errMsg = error.response.statusMessage;
            // return ErrorEntity(code: errCode, message: errMsg);
            switch (errCode) {
              case 400:
                return ErrorEntity(code: errCode, message: "请求语法错误");
              case 401:
                return ErrorEntity(code: errCode, message: "没有权限");
              case 403:
                return ErrorEntity(code: errCode, message: "服务器拒绝执行");
              case 404:
                return ErrorEntity(code: errCode, message: "无法连接服务器");
              case 405:
                return ErrorEntity(code: errCode, message: "请求方法被禁止");
              case 500:
                return ErrorEntity(code: errCode, message: "服务器内部错误");
              case 502:
                return ErrorEntity(code: errCode, message: "无效的请求");
              case 503:
                return ErrorEntity(code: errCode, message: "服务器挂了");
              case 505:
                return ErrorEntity(code: errCode, message: "不支持HTTP协议请求");
              default:
                {
                  // return ErrorEntity(code: errCode, message: "未知错误");
                  return ErrorEntity(
                    code: errCode,
                    message: error.response != null
                        ? error.response!.statusMessage!
                        : "",
                  );
                }
            }
          } on Exception catch (_) {
            return ErrorEntity(code: -1, message: "未知错误");
          }
        }
      default:
        {
          return ErrorEntity(code: -1, message: error.message ?? "");
        }
    }
  }

  /*
   * 取消请求
   *
   * 同一个cancel token 可以用于多个请求，当一个cancel token取消时，所有使用该cancel token的请求都会被取消。
   * 所以参数可选
   */
  void cancelRequests(CancelToken token) {
    token.cancel("cancelled");
  }

  UserInfo userinfo = UserInfo();

  /// 读取本地配置 用户header 包装
  Map<String, dynamic>? getAuthorizationHeader() {
    var headers = <String, dynamic>{};

    /// * [appSystem] - 对应系统，1 - Android，2 - Apple
    /// * [version] - 接口版本号
    /// * [appVersion] - APP版本号
    /// * [language] - 当前语言环境
    /// * [deviceid] - 唯一设备码
    /// * [brandName] - 手机品牌
    /// * [modelName] - 机型
    /// * [authorization] - Bearer 登录后返回的令牌
    headers['app-system'] = Platform.isIOS ? 2 : 1; // 1 - Android，2 - Apple
    headers['version'] = '1.0.0';
    headers['app-version'] = '1.1.0';

    if (userinfo.language != null) {
      headers['language'] = userinfo.language;
    } else {
      if (ConfigStore.to.locale!.languageCode == 'zh') {
        headers['language'] = 'hant';
      } else {
        headers['language'] = ConfigStore.to.locale!.languageCode ?? "en";
      }
    }

    headers['deviceid'] = DeviceInfoService().deviceId;
    headers['brand-name'] = DeviceInfoService().brand;
    headers['model-name'] = DeviceInfoService().model;
    if (userinfo.token.isNotEmpty) {
      headers['Authorization'] = 'Bearer ${userinfo.token}';
    }
    // if (Get.isRegistered<UserStore>() && UserStore.to.hasToken == true) {
    //   headers['Authorization'] = 'Bearer ${UserStore.to.token}';
    // }
    return headers;
  }

  // 根据值查找对应的所有键
  List<String> findKeysByValue(Map<String, int> map, int targetValue) {
    List<String> result = [];
    for (MapEntry<String, int> entry in map.entries) {
      if (entry.value == targetValue) {
        result.add(entry.key);
      }
    }
    return result;
  }

  /// restful get 操作
  /// refresh 是否下拉刷新 默认 false
  /// noCache 是否不缓存 默认 true
  /// list 是否列表 默认 false
  /// cacheKey 缓存key
  /// cacheDisk 是否磁盘缓存
  Future get(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    bool refresh = false,
    bool noCache = !CACHE_ENABLE,
    bool list = false,
    String cacheKey = '',
    bool cacheDisk = false,
  }) async {
    Options requestOptions = options ?? Options();
    if (requestOptions.extra == null) {
      requestOptions.extra = Map();
    }
    requestOptions.extra!.addAll({
      "refresh": refresh,
      "noCache": noCache,
      "list": list,
      "cacheKey": cacheKey,
      "cacheDisk": cacheDisk,
    });
    requestOptions.headers = requestOptions.headers ?? {};
    Map<String, dynamic>? authorization = getAuthorizationHeader();
    if (authorization != null) {
      requestOptions.headers!.addAll(authorization);
    }

    var response = await dio.get(
      path,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    );
    return response.data;
  }

  /// restful post 操作
  Future post(
    String path, {
    Map<String, dynamic>? data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) async {
    logd('请求网络接口 $path');

    // 新增：检查网络状态
    late NetworkService networkService = Get.find<NetworkService>();

    // bool isApiReachable = Get.find<NetworkService>().isApiReachable;

    if (!networkService.isApiReachable) {
      // EasyLoading.showError('无网络连接，请检查网络设置'.tr);
      // return null; // 无网络时返回 null，终止请求
      networkService.showNoNetworkAlert();
    } else {
      // Loading.show();
      //编辑 headers
      Options requestOptions = options ?? Options();
      requestOptions.headers = requestOptions.headers ?? {};
      Map<String, dynamic>? authorization = getAuthorizationHeader();
      if (authorization != null) {
        requestOptions.headers!.addAll(authorization);
      }
      FormData formData;
      if (kDebugMode ? false : true) {
        // 加密数据
        Map<String, dynamic> encrypted = EncryptionUtils.encryptData(data);
        // log('加密结果: $encrypted');
        formData = FormData.fromMap(encrypted);
      } else {
        if (data == null) {
          data ??= {};
        } else {}
        formData = FormData.fromMap(data);
      }

      var response = await dio.post(
        path,
        data: formData,
        queryParameters: queryParameters,
        options: requestOptions,
        cancelToken: cancelToken,
      );

      // Map<dynamic, dynamic> decrypted = {};
      // ignore: prefer_typing_uninitialized_variables
      var parsed;
      if (kDebugMode ? false : true) {
        parsed = EncryptionUtils.decryptData(response.data as String);
        // print('解密结果: $decrypted');
      } else {
        parsed = jsonDecode(response.data);
      }

      log('解析后: $parsed');

      if (parsed['code'] == 1) {
        bool hasData = parsed.containsKey('data');
        if (hasData) {
          return parsed['data'];
        } else {
          return parsed;
        }
      } else {
        return parsed;
      }
    }
  }

  /// restful put 操作
  Future put(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.headers = requestOptions.headers ?? {};
    Map<String, dynamic>? authorization = getAuthorizationHeader();
    if (authorization != null) {
      requestOptions.headers!.addAll(authorization);
    }
    var response = await dio.put(
      path,
      data: data,
      queryParameters: queryParameters,
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response.data;
  }

  /// restful patch 操作
  Future patch(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.headers = requestOptions.headers ?? {};
    Map<String, dynamic>? authorization = getAuthorizationHeader();
    if (authorization != null) {
      requestOptions.headers!.addAll(authorization);
    }
    var response = await dio.patch(
      path,
      data: data,
      queryParameters: queryParameters,
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response.data;
  }

  /// restful delete 操作
  Future delete(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.headers = requestOptions.headers ?? {};
    Map<String, dynamic>? authorization = getAuthorizationHeader();
    if (authorization != null) {
      requestOptions.headers!.addAll(authorization);
    }
    var response = await dio.delete(
      path,
      data: data,
      queryParameters: queryParameters,
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response.data;
  }

  /// restful post form 表单提交操作
  Future postForm(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.headers = requestOptions.headers ?? {};
    Map<String, dynamic>? authorization = getAuthorizationHeader();
    if (authorization != null) {
      requestOptions.headers!.addAll(authorization);
    }
    var response = await dio.post(
      path,
      data: FormData.fromMap(data),
      queryParameters: queryParameters,
      options: requestOptions,
      cancelToken: cancelToken,
    );

    return response.data;
  }

  /// restful post Stream 流数据
  Future postStream(
    String path, {
    dynamic data,
    int dataLength = 0,
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions.headers = requestOptions.headers ?? {};
    Map<String, dynamic>? authorization = getAuthorizationHeader();
    if (authorization != null) {
      requestOptions.headers!.addAll(authorization);
    }
    requestOptions.headers!.addAll({
      Headers.contentLengthHeader: dataLength.toString(),
    });
    var response = await dio.post(
      path,
      data: Stream.fromIterable(data.map((e) => [e])),
      queryParameters: queryParameters,
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response.data;
  }
}

// 异常处理
class ErrorEntity implements Exception {
  int code = -1;
  String message = "";
  ErrorEntity({required this.code, required this.message});

  String toString() {
    if (message == "") return "Exception";
    return "Exception: code $code, $message";
  }
}
